﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using XingLucifer.IBase;
using XingLucifer.IBase.Enums;

namespace XingLucifer.Devices
{
    public class TCPCom : ICommunication
    {
        public TCPCom(byte suffixIP, string ip, int port, DeviceTypes deviceTypes, int index, TaskTypes taskType, string serviceName, CancellationTokenSource token, EndianTypes endianTypes)
        {
            _ip = ip;
            _port = port;
            _deviceTypes = deviceTypes;
            _suffixIP = suffixIP;
            _index = index;
            _cacheByte = new List<byte>();
            _endianTypes = endianTypes;
            _socketToken = token;
            _taskType = taskType;
            _serviceName = serviceName;
            timeout = 2000;
        }
        public int Receive(byte[] buffer) => _socket.Receive(buffer);

        #region 属性
        private Stopwatch _stopwatch = new Stopwatch();
        protected System.Net.Sockets.Socket _socket;
        protected CancellationTokenSource _socketToken;
        protected EndianTypes _endianTypes;
        protected byte _suffixIP;
        private string _ip;
        private int _port;
        private DeviceTypes _deviceTypes;
        private int _index;
        protected List<byte> _cacheByte;
        protected IBase.IProtocol _protocol;
        private TaskTypes _taskType;
        private string _serviceName;
        private int timeout;

        public string IP => _ip;
        public int Port => _port;
        public DeviceTypes DeviceType => _deviceTypes;
        public int Index => _index;
      //  public int Timeout { get; set; }
        public int Timeout { get { return timeout; } set { if (_socket != null) { timeout = value; _socket.SendTimeout = _socket.ReceiveTimeout = timeout; } } }


        public Func<ICommunication, int, string, int, DeviceTypes, TaskTypes, string, CancellationTokenSource, bool> ReconnectDisconnection { get; set; }
        public TaskTypes TaskType { get => _taskType; }
        public string ServiceName { get => _serviceName; }

        public EndianTypes EndianType => _endianTypes;

        #endregion
        #region Synchronize
        private volatile int _lock = 0;
        protected void Locked()
        {
            int lockNumber = 0;
            while (Interlocked.Exchange(ref _lock, 1) != 0)
            {
                _ = 0; _ = 0; _ = 0; _ = 0; _ = 0; _ = 0; _ = 0; _ = 0; _ = 0; _ = 0; _ = 0; _ = 0; _ = 0; _ = 0; _ = 0; _ = 0;
                if (++lockNumber > 50)
                {
                    Thread.Sleep(1);
                    lockNumber = 0;
                }
            }
        }

        protected void UnLock() => Interlocked.Exchange(ref _lock, 0);
        #endregion

        public byte[] Read(int length)
        {
            if (_socket != null)
            {
                try
                {
                    byte[] bytes = new byte[length];
                    length = _socket.Receive(bytes, SocketFlags.None);
                    return bytes.Take(length).ToArray();
                }
                catch (Exception)
                {
                    if (_socketToken != null && !_socketToken.Token.IsCancellationRequested)
                    {
                        Thread.Sleep(100);
                        ReconnectDisconnection?.Invoke(this, Index, IP, Port, DeviceType, TaskType, ServiceName, _socketToken);
                    }
                    return new byte[0];
                }
            }
            return new byte[0];
        }
        public string Read()
        {
            if (_socket != null)
            {
                try
                {
                    byte[] bytes = new byte[1024];

                    var len = _socket.Receive(bytes, SocketFlags.None);

                    return Encoding.ASCII.GetString(bytes.Take(len).ToArray());
                }
                catch (Exception)
                {
                    if (_socketToken != null && !_socketToken.Token.IsCancellationRequested)
                    {
                        Thread.Sleep(100);
                        ReconnectDisconnection?.Invoke(this, Index, IP, Port, DeviceType, TaskType, ServiceName, _socketToken);
                    }
                    return null;
                }
            }
            return null;
        }

        public bool Write(byte[] buffer)
        {
            if (_socket != null)
            {
                _socket.Send(buffer);
                //int length = _socket.Send(buffer, SocketFlags.None);
                //if (length == buffer.Length)
                //{
                //    return true;
                //}
            }
            return true;
        }

        /// <summary>
        /// 读取短路测试仪值
        /// </summary>
        /// <param name="keyValuePairs"></param>
        /// <param name="timeoutDuration"></param>
        /// <returns></returns>
        public Dictionary<string, string> SendAndReceive(Dictionary<string, string>  keyValuePairs)
        {
            Dictionary<string, string> responseDict = new Dictionary<string, string>();

            try
            {
                foreach (var kvp in keyValuePairs)
                {
                    string key = kvp.Key; // 获取命令的键
                    string command = kvp.Value; // 获取命令的值

                    byte[] buffer = Encoding.ASCII.GetBytes(command); // 将命令字符串转换为字节数组
                    _socket.Send(buffer); // 发送命令数据到服务器
                    Thread.Sleep(100);

                    if (_socket.Available > 0)
                    {
                        byte[] receiveBuffer = new byte[1024]; // 设置接收缓冲区大小
                        int receivedBytes = _socket.Receive(receiveBuffer); // 接收服务器返回的数据
                        string response = Encoding.ASCII.GetString(receiveBuffer, 0, receivedBytes); // 将接收到的字节数组转换为字符串
                        responseDict.Add(key, response); // 将命令的响应存储到字典中
                    }
                    else
                    {
                        responseDict.Add(key, string.Empty); // 超时时赋值为空字符串
                    }
                }
            }
            catch (Exception ex)
            {
                return null;
                // 处理异常
                //Logger.Info(string.Format("{0}号短路测试仪 {1}:{2} 发生了异常:{3}", ID, IP, Port, ex.Message), "Log", LevelType.Error, false);
            }

            return responseDict;
        }
        public bool Open()
        {
            try
            {
                _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                _socket.ReceiveTimeout = 1000;
                _socket.SendTimeout = 1000;
                string[] ip = IP.Split('.');
                //_socket.Bind(new System.Net.IPEndPoint(System.Net.IPAddress.Parse($"{ip[0]}.{ip[1]}.{ip[2]}.{_suffixIP}"), 0));
                _socket.Connect(new IPEndPoint(IPAddress.Parse(IP), _port));
            }
            catch (Exception)
            {
                return false;
            }
            return true;
        }

        public void Close()
        {
            if (_socket != null)
            {
                try
                {
                    _socket.Close();
                    _socket.Dispose();
                }
                catch (Exception)
                {
                }
                _socket = null;
            }
        }

        //public byte[] SendToRead(byte[] bytes, int count)
        //{
        //    for (int i = 0; i < count; i++)
        //    {
        //        try
        //        {
        //            Locked();
        //            _socket.Send(_protocol.Serialize(bytes));
        //            List<byte> list = new List<byte>();
        //            byte[] buffer = new byte[1024];
        //            int length = _socket.Receive(buffer);
        //            list.AddRange(buffer.Take(length));
        //            while (!_protocol.Verify(list))
        //            {
        //                length = _socket.Receive(buffer);
        //                list.AddRange(buffer.Take(length));
        //            }
        //            UnLock();
        //            return _protocol.Deserialize(list);
        //        }
        //        catch (Exception ex)
        //        {
        //            Console.WriteLine(ex.ToString());
        //            UnLock();
        //            if (count == 1
        //                || (_socketToken != null && _socketToken.Token.IsCancellationRequested)
        //                || ex.ToString().Contains("远程主机关闭") || ex.ToString().Contains("CIP"))
        //            {
        //                Console.WriteLine(ex.ToString());
        //                return default;
        //            }
        //            if (_socketToken != null && !_socketToken.Token.IsCancellationRequested)
        //            {
        //                Thread.Sleep(100);
        //                ReconnectDisconnection?.Invoke(this, Index, IP, Port, DeviceType, TaskType, ServiceName, _socketToken);
        //            }
        //        }
        //    }
        //    return default;
        //}


        public byte[] SendToRead(byte[] bytes, int count)
        {
            for (int i = 0; i < count; i++)
            {
                try
                {
                    Locked();
                    _socket.Send(bytes);
                    List<byte> list = new List<byte>();
                    byte[] buffer = new byte[1024];
                    int length = _socket.Receive(buffer);
                    //list.AddRange(buffer.Take(length));
                    //while (!_protocol.Verify(list))
                    //{
                    //    length = _socket.Receive(buffer);
                    //    list.AddRange(buffer.Take(length));
                    //}
                    length = _socket.Receive(buffer);
                    list.AddRange(buffer.Take(length));
                    UnLock();

                    return list.ToArray();
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.ToString());
                   
                }
            }
            return default;
        }

        public void SetProtocol(IProtocol protocol)
        {
            _protocol = protocol;
        }



    }
}
